Hey there.
Welcome back.
We're going to jump right into this lecture by starting to script our admin handler on the server.
The purpose of this script is to check for when players either type commands in their chat, or use
their GUIs to fire an event to execute commands.
So let's go ahead and get started.
Inside of the script we're going to need four services.
One is going to be the player service.
That way we can get access to players that join our game and set up any functionality for their chat
events.
And then we're going to need replicated storage as well.
We're going to need the data store service, and we're going to use this to store any players we want
to add into the data store to become permanent admins in our game.
And then we're also going to need the run service and you'll see why in a moment.
Now inside of our variable section we're going to create a new data store.
I'm just going to call it Admin data store.
Now we're going to refer to our data store service and use the Get Data Store function to either get
or create a new data store if it doesn't exist.
And we're just going to call this data store admin ranks.
And then from this point, we need to refer to all of the other assets we have in replicated stores.
So first I'm going to make a reference to the folder.
I'll just call it admin assets equal to Replicated Storage and get that folder.
And then we can get, you know the request event that's inside of there.
So admin assets dot request get that remote function.
We'll have one for communicating between the client and server.
And then we'll also have one for communicating between different server scripts.
So we're going to be using our commands module script to execute commands.
And sometimes this module script may need to communicate back with the main script that required it.
So that's what we're going to use that Bindable for.
And then we're also going to require all of the different module scripts we have.
So first we need to require our admin settings.
So require inside of our admin assets.
Get settings will require our admin enum as well.
And we're also going to require our commands.
Module script.
And then I'm also going to make a reference to the guy that is inside of that folder.
So inside of our admin assets we have our guy for admin.
So I'll just call this admin guy and we'll refer to that inside of that folder.
The last thing I want to keep track of is I want to keep track of all of the functions that are connected
to different players.
Uh, chat events.
So different player objects have an event called chatted or I believe it's chat.
And sometimes we may want to disconnect those functions that are attached to each of those players event.
In the case that maybe we un admin them, or we add new admin and then remove it later or something
like that.
So we can store all of those connections in a table.
And we're just going to call it connections.
Now some of the functions we're going to need are we're actually one we'll need is we're going to have
to steal this one we created inside of our commands module script.
So we're going to use that here as well I want to have a function for getting the rank of a player that
is in our game.
So we'll pass a player object to this function and it'll return back to us a number that represents
their rank.
I also want to have a function and I'm going to call it get player from string.
And this function will will pass.
Somebody called a caller the person who called this function.
And that's going to be a player.
And then we're also going to have a string in here.
And this function is either going to return an empty table or a table with player objects inside of
it.
So the purpose of this function is that let's say a player uses a command and we need to get a player
for that command.
So let's say they use the word like me or they use the word others or all.
We either need to get just the player itself.
We either need to get every other player in the game besides the caller, or we need to get every single
player in the game or a specific player.
And that's going to be the purpose of this function.
The next function we'll need is to execute a command.
And this function will take a player.
So the person who is executing the function.
And we're going to get the message they sent to us either in chat or through an event.
And this is going to take that message and split it up into its different components.
So if they do a command like kill others, then it'll split up the message into kill and then others.
And then based on that, we're going to extract information, uh, based on the different parameters
for a command.
And this function can also return either a boolean.
And a string possibly.
So we'll have this function either return true, or if we encountered a problem trying to execute a
command, we'll do return false and some error message.
So we'll do something like that.
The next function we'll need is for removing admin from a player.
So we'll just call it remove admin from and we'll pass a player to this.
And then we'll need a function to set up admin or give admin to a player.
So we'll call it um setup admin for.
And again we'll pass a player object to this function.
Now, some of the different events we're going to need to listen to are going to be when a player gets
added into our game.
So the player added event, we're going to connect a function to this and get that player.
And depending on whether or not this player is an admin, we can try to set up admin for them.
Um, we're going to need to listen to our request remote function.
So on server invoke we're going to set it equal to a new lambda function.
And we're going to kind of set it up like we've done in the past, where we have the player that has
called this function.
They're giving us an action to do.
So that's going to be a string.
And they're passing any other arguments to go with that action.
And then we're also going to listen to our coms Bindable.
On invoke and again set it up with a lambda function.
And since this is not a remote function, we don't get a player object.
Instead we just get the action and the arguments for that action.
All right.
We've got everything set up.
So let's go ahead and start filling out these different sections.
So inside of the git rank function we need to be able to determine the rank of a player that we pass
to this function.
Now since we are going to be storing all of the players IDs as a string.
So let me go to the settings, since their id is going to be stored as a string.
That way we set up these tables as dictionaries and we do not set them up as arrays.
Then we need to create a key for this player.
So I'm going to call it key.
And we're going to use the two string function to convert their user ID into a string.
And then from this point, we can use this key to check whether or not they have a rank.
So I'm going to create a variable called rank.
And we're going to set it equal to.
We're going to first check the admin settings dot player ranks to see if the player exists within our
hard coded table here.
So if they have this rank in here or we could check if they exist within the temporary mods table,
pass the key as well.
So we're going to get that rank and then we can check, um, if there is no rank.
So they weren't stored in the player ranks table or the temporary mods table, then we should check
the data store.
However, I only want to do this on an actual server.
So if you're testing your game out in studio, uh, you don't really want to mess with data stores at
all in studio.
So that's why we need the run service in here, to make sure that we're not running in studio so we
can do and not run service is studio.
So if we're not running in studio, then we can, uh, call a function in our data store to get any
data for this particular player.
And of course, since a data store is going to be interacting with the cloud, we need to wrap it in
a call function in case it errors.
So we can create two variables, one called success and result equal to the p call function.
And in here we're going to pass the admin data store.
And the function we want to use is the get async function.
And then we need to pass any other information to this particular function.
Now you need to know something.
When we use our admin data store admin data store the function get async uses a colon.
And what do we know about using colons?
Well that means the data store itself gets automatically passed to the function as self.
So that means the first argument we need to pass to this function is the data store itself.
So admin data store.
That is the first argument we have to pass to this function.
And then the second argument we can pass is just the key.
So this is basically doing the exact same thing as this is doing right here.
But we're just wrapping it in a p call in case it errors.
So maybe their server is down or some internet error happens.
Whatever.
We just got to make sure to wrap it in a protected call function.
After that we can check if we were successful.
So if success, then what we could do is we could set rank equal to the result and that's it.
And then at the very end here, what we could do is we can return, uh, if rank, then we'll just return
rank.
Otherwise we're going to return zero.
So let's say they didn't have a rank in these tables and they don't have a rank in the data store.
Well that means they are a non-admin.
So we should return zero.
Otherwise if we did get a result from either of these tables or the data store, then we're going to
return that rank back in this function.
Okay.
So let's go ahead and start filling out our guitar player from string function.
So the first thing I want to do is I want to check, uh, whether or not the string is going to be equal
to different elements.
So if the string and we're going to call the lower function on it to make it all lowercase, that way
we can, uh, you know, stay consistent because in case somebody types capitals like capital M or capital
others like maybe they do this or they do this, we want to lowercase it to make it, you know, easy
to recognize in our script.
So if the string is equal to me.
Then we can just return a new table with the caller of this function inside of it.
So it just returns the player back to where this function was called.
Otherwise, if this string is equal to something like all, then we can just return a table from players
and we just get all of the players in the game.
If the string is equal to others.
Then what we could do is we could create a table, call it others, and we'll use players, get players.
And remember, we need to remove the collar out of this table so we can do table dot remove inside of
others.
And we want to remove at the index.
We're going to use the table dot find function to find uh where the player is stored in this table.
So others.
Collar, so it's going to return back to us a number wherever our collar is stored in this table.
And then we remove it out of our others table, and then we can just return that otherwise.
If they didn't put me all or others, then that means we need to search for a particular player in our
game.
So the first thing we can do is we can create a variable called player, and we'll set it equal to players.
And we're going to find first child with the string.
Now that's probably not going to work unless they type their name out perfectly.
So in case we do not have a player, then what we need to do is we need to loop through every single
player inside of players, get players.
So we got to go through every single player in our game.
And what we need to do is we need to check if their name.
And we're going to get a substring of their name.
So we're going to use the sub function.
And we're going to start at the index of one and go all the way to the max length of our string that
was passed to this function.
And then we also got to make sure to set it to lowercase.
So if all of that is not equal to our string.
Then we're just going to continue looping.
So what this is doing is let's say we do something like kill uh c right.
Let's say they only put the letter C.
Well, what this is going to do is it's going to loop through every single player in our game, and
it's going to find the first player whose name starts with C, because we're getting a substring here.
So this will only store the string of C because the length of our string is only one character.
So if we do find a match then we can just set player equal to player.
And then once this loop is over then we can go ahead and return player inside of a new table.
However, we only want to return that if the player actually exists in our game.
So if there is a player with this particular name in our game, then we're going to return a table with
them inside of it.
Otherwise, if we make it through all of that and we couldn't find a player at all, then we can just
return an empty table.
All right, so now let's get into our fun little function here.
And that's going to be executing commands.
So the purpose of this function is we're going to pass a player to it the person who's executing the
command and their message.
So for example they might type out something like set speed.
Others 140.
And what we need to do is we need to split up this string into different sections or arguments.
So one section needs to be the command, one section needs to be the first argument to this command,
and the second will be the second argument, and so on and so on.
If they have, you know, more parameters or arguments for this particular command.
And that's actually very easy to do.
And what we could do is we can create a table, I'm going to call it ARGs.
And we're going to use a function in the string library called split.
And what this does is it says right here splits a string into parts based on the defined separator.
And what's going to be our defined separator.
Well that's going to be a space.
Because if they do a command like set speed others.
The only thing separating each of these strings here is a space.
So we want to split it up based on the space.
And that's very easy.
So we can just pass the string here.
So the message and we want to split it up based on a space.
So now that means our argument table is going to be split up into a bunch of different strings.
Now since we're going to be, uh, connecting this function to whenever a player chats, not everything
that comes out of when a player chats is a command, right?
They might say hello or hi, and it might not be a command.
So we need to first verify that they're using the prefix that we defined inside of our settings module
script.
So what we can do is we can check if we're going to use the string sub function.
And we're going to get args one.
So we're getting a substring of the first argument from the first index to the admin settings.
Oops.
Admin settings get the prefix and get its length.
So we're basically just getting the first character.
And actually I think we need to use the length function not the hashtag function.
So there we go.
So this returns to us the length of the prefix which will just be one.
So we're going to get a substring of whatever they type.
So if they type something like this then it'll give us this prefix here.
Or if they type something like that it'll just give us the first character.
So if this first character is not equal to our admin settings dot prefix, then we're going to return
false.
And we'll give them a message like missing prefix or something like that.
The next thing we need to do is we need to verify the usage for the command.
So usage is going to be equal to string dot sub.
And we're going to do args one.
And we're going to start at the second index because we don't want to include the prefix.
And then we can just leave Jay blank.
That means it's going to default to negative one.
So we're getting a substring like this.
So somebody types set speed.
Then what this function is going to do is it's going to get a substring of that which will just be set
speed.
It just gets rid of the prefix for us.
And we'll lowercase it as well to make it easier.
And then what we could do is we could look to see if this command exists within the available commands
in our game.
So I'm going to create a variable called command.
And we're going to loop through every single command and pairs commands dot current commands.
So we're going to loop through every single command inside of our current commands table, and we're
going to check to see if we can find this usage.
Inside of any of the commands in our game.
So if table dot find inside of this command and get the usage table and we find this usage, then we
can just set command equal to command.
So if they use like something like set speed, it's going to look through all of our commands in the
game.
It's going to look inside these different usage tables and see if that string exists for these different
usages.
So if I had one in here like set speed and then I had another one for speed and whatnot, if it finds
that string within the usage table then we're going to grab this command.
However, if we did not find any command.
Then we can just return false and tell them that this command does not exist.
Another thing we can use is we can use our git rank function.
So we're going to get the rank of this player.
And we're going to ensure that their rank is at least greater than or equal to the minimum rank.
However, if their rank is less than the command dot minimum rank, then we need to return false and
tell them you do not have permission to use this command.
So if they try to use a command that only has owner privileges and they're not an owner, they won't
be able to execute it.
The next thing we need to verify is we need to verify that the number of arguments they passed to the
specific function actually matches the amount of arguments that is needed for the function.
So if you remember, we made this table called parameters and it stores all of the parameters or arguments
that are required for the function or the command.
And we need to verify that the player actually gave us enough arguments to execute the functionality
for this command.
So we need to check if the number of arguments.
And we're going to subtract this by one, because we don't want to include the prefix and the name of
the command.
If this is less than the number of parameters that's required for this particular command.
So dot parameters, then we're going to return false and say missing arguments to command.
Otherwise, if everything checks out, then what I'm going to do is I'm going to create a table, I'll
call it ARGs to pass.
And these are going to be the arguments we need to pass to the function.
And we're going to loop through every single parameter that is inside of our parameters table.
So for every single parameter type in ipairs command dot parameters.
What we can do.
Is, I'm going to create a variable called arg argument to be added.
And we're going to check the type for this particular parameter.
So if Pram type is equal to player.
So if they use the set speed function, obviously the first parameter type is going to be player.
Then we need to get the player.
So what we could do is we could set arg to be added equal to get player from string.
And we're going to pass, uh, the player that wants to execute this function.
And we're going to do args.
And we're going to get I and plus one.
And you're like well why are we adding one here.
We need to add one because again we are ignoring the very first string that's inside of our arguments
table, which is the prefix and the name of the command.
We don't want that.
We want to get the arguments and not the command name.
However, let's say this function doesn't return us anything.
Then what we could do is, uh, check if the number of elements in this table.
So remember this function returns back to us a table that contains players.
So if that table is empty, then.
Um, what we need to do is we need to return false and tell them no players, uh, exist.
Okay.
The next thing we need to check is if the parameter type is equal to number.
So if it's a number then what we need to do is we need to set arg to be added equal to.
And then we're going to use the function two number.
And we're going to pass args again I plus one because we need to ignore the prefix and the name of the
command.
Otherwise.
If the pram type is, let's say it's a string.
Then we need to do something a little bit different.
And that's because let's say one of our functions is kick and we kick some player, and then we need
to give them a message for why they got kicked.
So they're going to type out something like you've been bad.
Well because we use the string dot split function to split up the string based on the spaces.
Our string of you've been bad is going to be split up.
So that means we're going to have to retrieve the string message that they wanted.
And that means you're also going to have to, uh, place any functions that have string.
The string needs to be the last parameter.
Because what we're going to do here is I'm going to create a variable called text and set it to an empty
string.
And what we're going to do is we're going to loop, um, starting at this index plus one, because again,
we need to ignore the first index that's in our args table.
And we're going to loop through every single argument in our table.
And we're going to set text equal to itself.
And we're going to concatenate it with a new string.
And we're going to put a directive here which is going to be a string.
And we're going to put a space in front of it.
And then we're going to format the string with args n.
So for example.
If a player typed out a command like, uh, kick.
Others I kicked you.
Then what this is going to do is it's going to loop through every single argument inside of our table,
and it's going to be starting at this index plus one.
And since this parameter is also going to be the last one, if there was any other parameters that the
function required, it's going to skip it as well because we're adding plus one to I.
And that means we're going to get every single other argument inside of that table that's beyond the
other parameters.
So it's going to get each of these strings and it's going to stitch it to our text variable.
And that means our message will be fixed.
So instead of it being split up as I.
And then another string kicked and then another string you, we're connecting them all together to be
one cohesive message of I kicked you, and then we can set ARG to be added to this text.
Otherwise, if this particular parameter doesn't match any of these ones that we've hardcoded here,
then we can just set arg to be added equal to args I plus one.
Now we're not done yet because we need to verify some things first.
So specifically here.
If the type of our ARG to be added that we just created.
If it's equal to a table.
And we don't have anything inside of check for type in our table.
Argh!
To be added one.
And then we pass the parameter type.
So if whatever is stored within our table is not equal to the parameter type we expect.
Or let's say that the type of our ARG to be added.
Is not equal to table.
And.
We do not get the argument, we expect for ARG to be added with this particular parameter type.
Then what we could do.
And then I'm going to indent this to make it a little clearer.
What we could do is we could return false and give them a message like command.
And inside of like two brackets we can place a directive, uh, this command expected.
And put another directive here as a string.
So expected this type for argument number.
And we're going to put another directive that's going to be a number.
So percentage D.
So let's say we use a command speed and we expect a number for argument.
Let's say number two.
But we didn't get that.
Then we're just going to say got put another directive got this instead.
Bear with me here.
And then we're going to call the format function and pass command dot name the param type.
And then I for the number and then type of and we're going to pass args here we're going to get I and
add one to it.
Okay, so what is this?
What am I doing here?
So we're looping through every single parameter type that is required for this function.
And we're setting arg to be added to either, uh, any of these things based on whether or not we require
player A number or a string, or if it's not any of that, then we just set it to itself, and then
we're checking to ensure that this argument that needs to be added is actually the expected type that
we need for this particular command.
So we got to make sure it equals this parameter type.
The thing we just got, if it isn't then we're going to tell them we didn't get the correct argument
for the parameter that we need in our function.
So we're going to tell them like command set speed expected number for argument number three.
But we got a string instead as an example.
So these checks here help to ensure that these commands are getting the correct arguments passed to
them.
Because if they don't well our commands are going to error and we don't want that to happen.
Otherwise, if we make it past all of these checks and everything is good, then we can use table.insert
inside of our args to pass table and insert arg to be added.
And then once we're finally done looping through all the required parameters for this particular command,
then we can use our command and use the callback function inside of it, and pass the player that wants
to execute the command.
And then all of the arguments we need to pass, and we can use the unpack function here and pass args
to pass.
And what this does is it's going to split up every single argument in our table to be, uh, separate
arguments to the function.
So if there is three different arguments in here, then it would split it up like, you know, as three
different arguments being passed to the function and not in a table.
So unpack args to pass.
And since we expect that this callback function is going to return back to us a boolean and a string,
we'll call it success and the result from this function.
If we were somehow not successful in executing this function, so if not success, then we're going
to return false.
And again give them a message like the command.
And we're going to put a directive in here.
The command encountered a problem.
During execution.
And the problem is we'll put another directive here to say the problem is this.
We're going to format this with the command dot name and then the result from our callback function.
So if somehow any of our commands encounter a problem, then we're going to tell the person who executed
the function or the command that, hey, this command encountered a problem, and the problem was this.
And that's going to be told to us from our callback function.
Otherwise we just return true here.
Meaning that we executed successfully.
All right.
So now let's set up our remove admin from function.
This one should be fairly straightforward.
First we need to create a variable as the key for this player.
So two string.
And we're going to get the players dot user ID.
And we're going to check if this player has a key value pair within our connections table first of all.
So if they exist in here then what we need to do is we need to access that connection they have in there,
which would be connected to their chatted event.
And we need to disconnect that.
And then we can set their connections key value pair equal to nil.
So equal to nil.
And that's it.
And then we need to check if they have a guy on them.
So if player dot player guy then we're going to find first child admin guy.
That's the name of our guy.
And if they have this guy then we're just going to destroy it.
All right.
And I'm pretty sure that's all we need to do for that function.
All right.
So now let's go ahead and set up our setup admin for function.
So first we need to check if our player is an admin if they aren't.
So if their rank is equal to admin enum dot non-admin.
Well then we just need to return out of this function and not do anything because we don't care about
this player.
Otherwise, if they do have admin, then what we need to do is first we need to remove admin from this
player or aka.
We need to disconnect any previous charted events and destroy any guys in their player guy folder in
case they have it.
So this is for like when you have a moderator in your game and you want to promote them to administrator,
well, they need to re-update their roles and re-update their guy.
So we need to destroy their old ones and then give them new ones.
So we're going to remove admin from this player.
And then what we could do is inside our connections table, we can use the two string function and get
their player dot user ID.
So this is their key again.
And we're going to set it equal to player dot chatted.
There's that event and we're going to connect a function to this.
And when they chat they're going to give us a message that they chatted.
And we're going to execute this command so we can do success.
And result is equal to execute command.
And we're going to pass the player and the message.
And if we were not successful in executing this command.
Then we need to tell this player that something went wrong.
And there's actually a frame inside of our admin GUI, like I showed in the previous lecture, that
we can display a message to them.
So that's what we're going to use the comms event for, is that we're going to fire to this client,
this player, and we're going to tell them to do an action like display a message.
So display message and the message is going to be the result from our execute command function.
So it's going to tell them exactly what went wrong when they were trying to execute the function.
And once we've got that done we need to give the player a GUI.
So I'm going to create a clone of IT admin GUI clone.
And we're going to set the clone dot parent equal to this players dot player GUI folder.
Alrighty.
The next thing we need to do is fill out our event handlers.
So what do we want to do when a player gets added to our game?
Well, first we want to get their key or a.k.a their user ID as a string.
So two string player dot user ID.
Now the first thing I want to check actually is to see if they exist within our server bans table within
our settings module script.
So if inside of admin settings not admin assets, admin settings, dot server bans and we pass this
key in there, if their user ID is in there, then we need to kick them because they're banned.
Right.
So we can do player kick and we'll give them a message.
And actually what we're going to do is when we create our ban command, we're going to store the message
of whoever banned them forever for the duration of the server's lifetime.
And we're actually going to store it inside of our server bans table.
So if we ban a player, then we'll have a key that's their user ID like this.
And what's going to be assigned to that key is a message like you are banned because of some reason,
right?
So what we could do is we could just pass admin settings.
Dot server bands and get the value that is stored at this key, which should be a string.
Otherwise, if they're not band, then we can call the setup admin for function and pass the player.
So every single player that joins our game, we're going to check whether or not they're an admin.
And if they are we need to set up admin for them.
Okay.
I'm pretty sure that's all we need to do for this particular event.
The next thing we should fill out is our on server invoke function for our request remote function.
Now there's really only a couple of things that I anticipate the player to request from the server.
One of the actions is going to be to execute a command.
So this is specifically for when they're using the GUI on their screen.
They're using that command line to execute a command.
They're not going to be doing it through the chat event, but instead they're going to be doing it through
their GUI.
Right?
So they're going to request to the server to execute a command.
And we can basically just do the exact same thing that we did for when a player chats.
Right.
Another action that I expect for them to do is to get their rank.
So if their action is equal to get rank, then we'll just supply the rank to them.
And this is because players can't access the data store on the client.
So at any time when the player requests to get their rank, then we're just going to give it to them.
Now before we actually start executing and stuff in here, we need to first verify that the arguments
that the player has given to this, uh, remote function is correct.
So what I can do is I'm going to create a variable called result, and we're going to set it equal to
the check arg for type.
And the argument is going to be our action.
And we want to make sure that it's a string.
If it's not a string.
So if not result, then we're going to return the result, which is going to be false.
And we're going to tell them that action of type put a directive here did not match expected type string.
And actually we can put this in little quotation marks.
And then we'll call the format function on this and pass the type of the action they pass.
So if an exploiter decides to be a little stupid and spam our remote functions with arguments that do
not match what we expect, then we're just going to tell them to shove it, go away, or basically just
go away.
We don't care.
Again, this is to make sure that your remotes are protected.
We always want to protect our remote functions and our remote events.
Otherwise, if that's good, then what we could do is we could fill out this section right here.
And I'm going to override result again with our check ARG for type.
And this time I want to make sure the argument they're passing in within our table is a string.
And that's the other thing actually, because we need to also verify that args is a table.
So we can do the same thing here.
Result equal to check arg for type args.
And we got to make sure it's a table.
If not results then we'll return results.
Expected table for arguments.
We'll just do that.
And then inside of here, we need to verify the contents inside of the table.
So basically whenever a player requests or uses this remote function, the only thing that should be
inside of this table is a string or aka their message or command.
Right?
The string should be something like kill, blah blah blah, whatever.
That should be the value inside of our table if it isn't for some reason.
So again, this is exploiters manipulating your remote functions and we're going to return false again
or aka the results.
And we're going to tell them that.
Argument one of type and we can just put a colon s here did not match expected type string.
And we can format this with the type of our args one.
And then put your end statement.
Otherwise, if that checks out, then we can just return the result from our execute command function.
So we're going to pass the player and then their message which is args one.
So we can actually make a note here args one should be a string.
And then for the git rank, this one's pretty easy.
We just need to return the value that is returned from our git ranked function.
And then if the action that the player requests doesn't match any of the ones that we have in here,
we're just going to return false and tell them, uh re requested action, put a directive did not match
any of the possible actions.
And again we're going to format this with the action that they passed to the server.
Okay, we're almost finished here.
The last thing we need to do is fill out this, and we're not going to fill it out completely yet,
because the purpose of this bindable here is mainly for when we're executing different commands.
So if we have commands in here, like to mod someone or set them or give them admin or give them permanent
admin or moderator, then we need to specifically do that from this script.
And that means this module script is going to request to this server script.
Hey, can you please set the admin or permanent admin for this player?
And that's the purpose of this Bindable.
So we can give some actions like if action is equal to uh, set temporary privileges.
Then we'll do that functionality in there.
If the action is to set permanent privileges.
Then we'll do the functionality in there.
Otherwise if the action is to remove privileges.
Then we'll do it in there.
Otherwise.
If the action is to get the rank of a player, we'll do a get rank action.
Then we can, you know, just return git rank args one, which should be a player.
Otherwise we'll just return false and say requested action did not match any of the possible actions.
Whatever.
Or we can actually just copy the exact same error message that we gave here.
So we're not going to fill out these just yet.
We're going to fill out those later when we actually create our different, uh, admin commands for
our admin system.
Other than that, our admin handler for the most part is complete.
And the next lecture we're going to start scripting our GUI on the client.
So I'll go ahead and see you there.